package com.pfzy.lib.net;

import android.content.Context;

import androidx.annotation.Nullable;

import com.pfzy.lib.net.convert.CCConverterFactory;
import com.pfzy.lib.net.convert.CCResponseConverter;
import com.pfzy.lib.net.cookie.NovateCookieManger;
import com.pfzy.lib.net.exception.ExceptionHandler;
import com.pfzy.lib.net.exception.IExceptionInterceptor;
import com.pfzy.lib.net.subscriber.CCSubscriber;
import com.pfzy.lib.net.ui.HttpDialogManager;
import com.pfzy.lib.net.ui.HttpToastManager;
import com.pfzy.lib.net.utils.UIUtil;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import okhttp3.ConnectionPool;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import retrofit2.Converter;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;

public class RxRetrofitClient {
    private static Builder rxBuilder;
    public static boolean debugMode;
    private static RxRetrofitClient mInstance;
    private Retrofit.Builder mBuilder;
    private OkHttpClient.Builder mOkHttpClientBuilder;
    private OkHttpClient mOkHttpClient;

    public static void init(Builder builder) {
        rxBuilder = builder;
        mInstance = createNewClient(builder);
        ExceptionHandler.mExceptionInterceptor = builder.mExceptionInterceptor;
        CCResponseConverter.sJsonRepair = builder.mJsonRepair;
        debugMode = builder.mDebugMode;
        CCSubscriber.updateSuccessCode(builder.mSuccessCode);
        UIUtil.setDialogManager(builder.mHttpDialog);
        UIUtil.setToastManager(builder.mHttpToast);
    }

    public static synchronized RxRetrofitClient createNewClient(Builder builder) {
        RxRetrofitClient client;
        synchronized (RxRetrofitClient.class) {
            client = new RxRetrofitClient();
            client.mOkHttpClientBuilder = createOKHttpBuilder(builder);
            client.mOkHttpClient = client.mOkHttpClientBuilder.build();
            client.mBuilder = new Retrofit.Builder().addCallAdapterFactory(RxJava2CallAdapterFactory.create()).client(client.mOkHttpClient);
            Converter.Factory factory = builder.mConvertFactory != null ? builder.mConvertFactory : CCConverterFactory.create(builder.mParser);
            client.mBuilder.addConverterFactory(factory);
        }
        return client;
    }

    private static synchronized OkHttpClient.Builder createOKHttpBuilder(Builder builder) {
        OkHttpClient.Builder okHttpClientBuilder;
        synchronized (RxRetrofitClient.class) {
            okHttpClientBuilder = new OkHttpClient.Builder()
                    .connectTimeout(builder.mConnectTimeout, TimeUnit.MILLISECONDS)
                    .readTimeout(builder.mReadTimeout, TimeUnit.MILLISECONDS)
                    .connectionPool(new ConnectionPool(8, 15L, TimeUnit.SECONDS))
                    .writeTimeout(builder.mWriteTimeout, TimeUnit.MILLISECONDS);
            if (builder.mContext != null) {
                // 设置可以接受传入HTTP响应中的cookie并为传出HTTP请求提供cookie的处理程序。
                okHttpClientBuilder.cookieJar(new NovateCookieManger(builder.mContext.getApplicationContext()));
            }
            if (builder.mInterceptors != null && builder.mInterceptors.size() > 0) {
                for (Interceptor interceptor : builder.mInterceptors) {
                    okHttpClientBuilder.addInterceptor(interceptor);
                }
            }
            // 网络拦截器
            if (builder.mNetInterceptors != null && builder.mNetInterceptors.size() > 0) {
                for (Interceptor interceptor2 : builder.mNetInterceptors) {
                    okHttpClientBuilder.addNetworkInterceptor(interceptor2);
                }
            }
        }
        return okHttpClientBuilder;
    }

    public static RxRetrofitClient getInstance() {
        if (mInstance == null) {
            throw new RuntimeException("ExRetrofitClient has not been initialized,call init(Builder builder) firse");
        }
        return mInstance;
    }

    /**
     * getHttp接口
     * @param baseUrl
     * @param interfaze
     * @param <T>
     * @return
     */
    public synchronized <T> T getHttpInterface(String baseUrl, Class<T> interfaze) {
        T proxy;
        final Object create = this.mBuilder.baseUrl(baseUrl).build().create(interfaze);
        proxy = (T) Proxy.newProxyInstance(create.getClass().getClassLoader(), new Class[]{interfaze}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable {
                if (args != null && args.length > 0) {
                    for (Object o : args) {
                        if (o instanceof Map) {
                            Iterator entries = ((Map) o).entrySet().iterator();
                            while (entries.hasNext()) {
                                Map.Entry next = (Map.Entry) entries.next();
                                if (next.getKey() == null || next.getValue() == null) {
                                    entries.remove();
                                }
                            }
                        }
                    }
                }
                return method.invoke(create, args);
            }
        });
        return proxy;
    }

    public static class Builder {
        private long mConnectTimeout = 10000;
        private long mReadTimeout = 10000;
        private long mWriteTimeout = 10000;
        private Context mContext;
        private List<Interceptor> mInterceptors = new ArrayList<>();
        private List<Interceptor> mNetInterceptors = new ArrayList();
        private IExceptionInterceptor mExceptionInterceptor;// 异常拦截器
        private Converter.Factory mConvertFactory;
        private HttpToastManager mHttpToast;
        private HttpDialogManager mHttpDialog;
        private boolean mJsonRepair = true;
        private boolean mDebugMode = false;
        private CCConverterFactory.ResponseJsonParser mParser;
        private int[] mSuccessCode;

        public Builder connectTimeout(int millisecond) {
            this.mConnectTimeout = millisecond;
            return this;
        }

        public Builder readTimeout(int millisecond) {
            this.mReadTimeout = millisecond;
            return this;
        }

        public Builder writeTimeout(int millisecond) {
            this.mWriteTimeout = millisecond;
            return this;
        }

        public Builder cookiesContext(Context context) {
            this.mContext = context.getApplicationContext();
            return this;
        }

        public Builder interceptor(Interceptor interceptor) {
            this.mInterceptors.add(interceptor);
            return this;
        }

        public Builder netInterceptor(Interceptor interceptor) {
            this.mNetInterceptors.add(interceptor);
            return this;
        }

        public Builder exceptionInterceptor(IExceptionInterceptor exceptionInterceptor) {
            this.mExceptionInterceptor = exceptionInterceptor;
            return this;
        }

        public Builder convertFactory(Converter.Factory factory) {
            this.mConvertFactory = factory;
            return this;
        }

        public Builder httpToast(HttpToastManager toast) {
            this.mHttpToast = toast;
            return this;
        }

        public Builder httpDialog(HttpDialogManager dialog) {
            this.mHttpDialog = dialog;
            return this;
        }
    }
}
